
#import <Cocoa/Cocoa.h>
#import <OpenGL/OpenGL.h>
#import <OpenGL/gl.h>

#import "CustomOpenGLView.h"

@implementation CustomOpenGLView

+ (NSOpenGLPixelFormat*)defaultPixelFormat
{
    NSOpenGLPixelFormatAttribute attribs[] = {0};
    return [[(NSOpenGLPixelFormat *)[NSOpenGLPixelFormat alloc] initWithAttributes:attribs] autorelease];
}

- (id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat*)format
{
    self = [super initWithFrame:frameRect];
    if (self != nil) {
        _pixelFormat   = [format retain];
    }
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_surfaceNeedsUpdate:) name:NSViewGlobalFrameDidChangeNotification object:self];
    return self;
}

- (void)dealloc
{   // get rid of the context and pixel format
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewGlobalFrameDidChangeNotification object:self];
    [self clearGLContext];
    [_pixelFormat release];
    
    [super dealloc];
}

- (void)setOpenGLContext:(NSOpenGLContext*)context
{
    [self clearGLContext];
    _openGLContext = [context retain];
}

- (NSOpenGLContext*)openGLContext
{   // create a context the first time through
     if (_openGLContext == NULL) {
        _openGLContext = [[NSOpenGLContext alloc] initWithFormat:_pixelFormat != nil ? _pixelFormat : [[self class] defaultPixelFormat] shareContext:nil];
        [_openGLContext makeCurrentContext];
		[self prepareOpenGL]; // call to initialize OpenGL state here
    }
    return _openGLContext;
}

- (void)clearGLContext
{
    if (_openGLContext != nil) {
        if ([_openGLContext view] == self) {
            [_openGLContext clearDrawable];
        }
        [_openGLContext release];
        _openGLContext = nil;
    }
}

- (void)prepareOpenGL
{
	// for overriding to initialize OpenGL state, occurs after context creation
}

- (BOOL)isOpaque
{
    return YES;
}

- (void)setPixelFormat:(NSOpenGLPixelFormat*)pixelFormat
{
    [_pixelFormat release];
    _pixelFormat = [pixelFormat retain];
}

- (NSOpenGLPixelFormat*)pixelFormat
{
    return _pixelFormat;
}

- (void)lockFocus
{
    // get context. will create if we don't have one yet
    NSOpenGLContext* context = [self openGLContext];
    
    // make sure we are ready to draw
    [super lockFocus];

    // when we are about to draw, make sure we are linked to the view
    if ([context view] != self) {
        [context setView:self];
    }

    // make us the current OpenGL context
    [context makeCurrentContext];
}

// no reshape will be called since NSView does not export a specific reshape method

- (void)update
{
    if ([_openGLContext view] == self) {
        [_openGLContext update];
    }
}

- (void) _surfaceNeedsUpdate:(NSNotification*)notification
{
    [self update];
}

- (void)encodeWithCoder:(NSCoder *)coder 
{

    [super encodeWithCoder:coder];
    if (![coder allowsKeyedCoding]) {
		[coder encodeValuesOfObjCTypes:"@iii", &_pixelFormat];
    } else {
		[coder encodeObject:_pixelFormat forKey:@"NSPixelFormat"];
    }
}

- (id)initWithCoder:(NSCoder *)coder 
{

    self = [super initWithCoder:coder];

    if (![coder allowsKeyedCoding]) {
		[coder decodeValuesOfObjCTypes:"@iii", &_pixelFormat];
    } else {
		_pixelFormat = [[coder decodeObjectForKey:@"NSPixelFormat"] retain];
    }
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_surfaceNeedsUpdate:) name:NSViewGlobalFrameDidChangeNotification object:self];
    
    return self;
}

@end
